package com.nineclock.attendance.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.nineclock.attendance.dto.AttendGroupDTO;
import com.nineclock.attendance.dto.AttendGroupPCExtraConfigDTO;
import com.nineclock.attendance.dto.AttendGroupPartDTO;
import com.nineclock.attendance.mapper.AttendGroupMapper;
import com.nineclock.attendance.mapper.AttendGroupPartMapper;
import com.nineclock.attendance.pojo.AttendGroup;
import com.nineclock.attendance.pojo.AttendGroupPart;
import com.nineclock.attendance.service.AttendGroupService;
import com.nineclock.common.entity.PageResult;
import com.nineclock.common.entity.Result;
import com.nineclock.common.enums.ResponseEnum;
import com.nineclock.common.exception.NcException;
import com.nineclock.common.threadLocal.CurrentUserHolder;
import com.nineclock.common.utils.BeanHelper;
import com.nineclock.system.feign.OrganizationFeign;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

@Service
@Slf4j
public class AttendGroupServiceImpl implements AttendGroupService {

    /**
     * 分页查看考勤
     */
    @Autowired
    private AttendGroupMapper attendGroupMapper;

    @Autowired
    private OrganizationFeign organizationFeign;
    @Autowired
    private AttendGroupPartMapper attendGroupPartMapper;

    @Override
    public PageResult<AttendGroupDTO> queryAttendGroupPage(Integer page, Integer pageSize) {

        //查看当前企业是否是初次使用,如果不是就添加一个考勤组
        LambdaQueryWrapper<AttendGroup> attendGroupQW = new LambdaQueryWrapper<>();
        attendGroupQW.eq(AttendGroup::getCompanyId, CurrentUserHolder.get().getCompanyId()); //用企业id去查找
        Integer count = attendGroupMapper.selectCount(attendGroupQW);
        //判断是否是第一次创建,
        if (count == 0) {
            //是就创建一个默认的
            AttendGroup attendGroup = this.buildDefaultAttendGroup();
            //将默认的保存到数据库
            attendGroupMapper.insert(attendGroup);

            //默认考勤要关联我们所有的员工(所有顶级部门)
            //查看我们顶级部门所有数据
            List<Long> departmentIds = organizationFeign.queryDepartmentIds().getData();
            //考勤组与部门关联
            if (CollectionUtil.isNotEmpty(departmentIds)) {
                for (Long departmentId : departmentIds) {
                    AttendGroupPart attendGroupPart = new AttendGroupPart();
                    attendGroupPart.setAttendGroupId(attendGroup.getId());//考勤组id
                    attendGroupPart.setObjectType(1);//部门
                    attendGroupPart.setObjectId(departmentId);//部门id
                    attendGroupPart.setAttendType(1);//参加
                    attendGroupPartMapper.insert(attendGroupPart);
                }

            }

        }

        //分页查询企业列表关系
        Page<AttendGroup> attendGroupPage = new Page<>(page, pageSize);
        LambdaQueryWrapper<AttendGroup> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(AttendGroup::getCompanyId, CurrentUserHolder.get().getCompanyId());
        Page<AttendGroup> attendGroupPage1 = attendGroupMapper.selectPage(attendGroupPage, wrapper);
        //获取考勤列表数据
        List<AttendGroup> records = attendGroupPage1.getRecords();
        //复制到AttendGroupDTO中
        List<AttendGroupDTO> attendGroupDTOS = BeanHelper.copyWithCollection(records, AttendGroupDTO.class);

        //循环所有所有列表数据
        for (AttendGroupDTO attendGroupDTO : attendGroupDTOS) {
            //把考勤组 关联的 关系数据查出来
            LambdaQueryWrapper<AttendGroupPart> attendGroupPartQW = new LambdaQueryWrapper<>();
            attendGroupPartQW.eq(AttendGroupPart::getAttendGroupId, attendGroupDTO.getId());

            List<AttendGroupPart> attendGroupParts = attendGroupPartMapper.selectList(attendGroupPartQW);
            //将部门和员工分开
            List<Long> departmentIds = attendGroupParts.stream()
                    .filter(attendGroupPart -> {
                        return attendGroupPart.getObjectType() == 1;
                    }).map(attendGroupPart -> {
                        return attendGroupPart.getObjectId();
                    }).collect(Collectors.toList());

            //统计部门对应的员工数量
            //统计每个考勤组 关联的员工数量
            Integer departmentIdCount = organizationFeign.queryUserCountByDepartmentIds(departmentIds).getData();

            //将员工分出来
            List<Long> userIds = attendGroupParts.stream().filter(attendGroupPart ->
                    attendGroupPart.getObjectType() == 2
            ).map(
                    attendGroupPart ->
                            attendGroupPart.getObjectId()
            ).collect(Collectors.toList());

            //将数据封装到attendGroupDTO里面
            attendGroupDTO.setMemberNum(departmentIdCount + (userIds == null ? 0 : userIds.size()));

        }
        PageResult<AttendGroupDTO> pageResult = new PageResult<>();
        pageResult.setTotalPage(attendGroupPage1.getPages());
        pageResult.setRows(attendGroupDTOS);
        pageResult.setTotal(attendGroupPage1.getTotal());


        return pageResult;
    }

    /**
     * 添加考勤
     */
    @Override
    public void addAttendGroup(AttendGroupDTO attendGroupDTO) {

        //健壮性判断
        if (attendGroupDTO == null) {
            throw new NcException(ResponseEnum.INVALID_PARAM_ERROR);
        }

        //复制转换
        AttendGroup attendGroup = BeanHelper.copyProperties(attendGroupDTO, AttendGroup.class);
        //设置基础信息
        attendGroup.setCompanyId(CurrentUserHolder.get().getCompanyId());//设置企业id
        attendGroup.setCreateTime(new Date());//创建时间
        attendGroup.setCreateUserId(CurrentUserHolder.get().getCompanyUserId()); //创建人id
        //设置工作日
        List<String> workdays = attendGroupDTO.getWorkdays();
        String workday = StrUtil.join(",", workdays);
        attendGroup.setWorkdays(workday);

        //设置得数日期
        List<AttendGroupPCExtraConfigDTO> extraConfigList = attendGroupDTO.getExtraConfig();
        //获取需要打卡时间
        List<Integer> needExtraConfig = extraConfigList.stream().filter(attendGroupPCExtraConfigDTO -> {
            return attendGroupPCExtraConfigDTO.getRequiredAttend() == 1;
        }).map(attendGroupPCExtraConfigDTO -> {
                    return attendGroupPCExtraConfigDTO.getRequiredAttend();
                }
        ).collect(Collectors.toList());

        //获取不需要打卡时间
        List<Integer> noExtraConfig= extraConfigList.stream().filter(attendGroupPCExtraConfigDTO -> {
            return attendGroupPCExtraConfigDTO.getRequiredAttend() == 0;
        }).map(attendGroupPCExtraConfigDTO -> {
            return attendGroupPCExtraConfigDTO.getRequiredAttend();
        }).collect(Collectors.toList());


        //设置必须打卡的日期
        attendGroup.setNecessaryTimeList(StrUtil.join(",",needExtraConfig));
        //设置不需要打开的日期
        attendGroup.setUnnecessaryTimeList(StrUtil.join(",",noExtraConfig));
        //保存考勤员工信息
        attendGroupMapper.insert(attendGroup);

        //设置参加考勤人员
        List<AttendGroupPartDTO> participates = attendGroupDTO.getParticipates();
        if (CollectionUtil.isNotEmpty(participates)) {
            for (AttendGroupPartDTO participate : participates) {
                LambdaQueryWrapper<AttendGroupPart> attendGroupPartQW = new LambdaQueryWrapper<>();
                attendGroupPartQW.eq(AttendGroupPart::getObjectId, participate.getObjectId()); //用户或者部门id
                attendGroupPartQW.eq(AttendGroupPart::getObjectType, participate.getObjectType()); //用户或者部门
                //删除关联
                attendGroupPartMapper.delete(attendGroupPartQW);
                //设置新的关系
                AttendGroupPart attendGroupPart = new AttendGroupPart();
                attendGroupPart.setAttendGroupId(attendGroup.getId()); //考勤组id
                attendGroupPart.setObjectType(participate.getObjectType());//用户或者部门
                attendGroupPart.setObjectId(participate.getObjectId());//部门id或或者用户id
                attendGroupPart.setAttendType(1);

                //保存新关系
                attendGroupPartMapper.insert(attendGroupPart);
            }
        }

        //设置无需考勤人员
        List<AttendGroupPartDTO> notParticipates = attendGroupDTO.getNotParticipates();
        if(CollectionUtil.isNotEmpty(notParticipates)) {
            for (AttendGroupPartDTO notParticipate : notParticipates) {
                LambdaQueryWrapper<AttendGroupPart> attendGroupPartQW = new LambdaQueryWrapper<>();
                attendGroupPartQW.eq(AttendGroupPart::getObjectId, notParticipate.getObjectId());
                attendGroupPartQW.eq(AttendGroupPart::getAttendType, notParticipate.getObjectType());

                //删除关系
                attendGroupPartMapper.delete(attendGroupPartQW);

                //设置新的关系
                AttendGroupPart attendGroupPart = new AttendGroupPart();
                attendGroupPart.setAttendGroupId(attendGroup.getId());//考勤组id
                attendGroupPart.setObjectId(notParticipate.getObjectId());
                attendGroupPart.setObjectType(notParticipate.getObjectType());
                attendGroupPart.setAttendType(2);

                //保存
                attendGroupPartMapper.insert(attendGroupPart);

            }

        }
    }


    /**
     * 根据用户id查询所在的考勤组
     * 1.查询员工id(从线程中
     * 2,根据员工id 查询 与考勤组的关系 ,如果能查到直接返回,如果没有,查询部门与考勤组的关系
     * 3.先查询员工所在的部门id集合,在根据部门id 查询所在的考勤组
     * */


    @Override
    public AttendGroupDTO getAttendGroupByUserId() {
        //1.从线程中获取用户id
        Long companyUserId = CurrentUserHolder.get().getCompanyUserId();
        //2.根据员工id 查询 与考勤组的关系 ,如果能查到直接返回,如果没有,查询部门与考勤组的关系
        LambdaQueryWrapper<AttendGroupPart> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(AttendGroupPart::getObjectId,companyUserId);//用户id
        wrapper.eq(AttendGroupPart::getObjectType,2);//用户

        AttendGroupPart attendGroupPart = attendGroupPartMapper.selectOne(wrapper);
        if (attendGroupPart==null){
            //3.先查询员工所在的部门id集合,在根据部门id 查询所在的考勤组
            //Long companyUserId = attendGroupPart.getObjectId();
            List<Long> departmentIds = organizationFeign.queryDepartmentsByUserId(companyUserId).getData();
            //判断查到的数据是否为空
            if (CollectionUtil.isNotEmpty(departmentIds)) {
                for (Long departmentId : departmentIds) {
                    LambdaQueryWrapper<AttendGroupPart> wrapper1 = new LambdaQueryWrapper<>();
                    wrapper1.eq(AttendGroupPart::getObjectType,1);
                    wrapper1.eq(AttendGroupPart::getObjectId,departmentId);
                    attendGroupPart = attendGroupPartMapper.selectOne(wrapper1);
                    if (attendGroupPart!=null){
                        break;
                    }

                }
            }

        }

        if (attendGroupPart==null){
            throw new NcException(ResponseEnum.USER_NOT_MATCH_ATTENDGROUP);
        }
        //从 考勤关联表中获取 考勤组id
        Long attendGroupId = attendGroupPart.getAttendGroupId();
        //然后通过考勤组id查询考勤组获取数据
        AttendGroup attendGroup = attendGroupMapper.selectById(attendGroupId);
        AttendGroupDTO attendGroupDTO = BeanHelper.copyProperties(attendGroup, AttendGroupDTO.class);
        //设置工作时间
        String workdays = attendGroup.getWorkdays();
        String[] split = workdays.split(",");
        attendGroupDTO.setWorkdays(Arrays.asList(split));
        return attendGroupDTO;
    }


    //创建
    public AttendGroup buildDefaultAttendGroup() {
        AttendGroup attendGroup = new AttendGroup();
        attendGroup.setName("秃头小分队");//默认考勤名称
        attendGroup.setCompanyId(CurrentUserHolder.get().getCompanyId());//企业id
        attendGroup.setStartWorkTime("09:00:00");//上班时间
        attendGroup.setAllowLateMinutes(10); //允许迟到分钟数
        attendGroup.setLateMinutes(30); //旷工迟到分钟数
        attendGroup.setStartNoonRestTime("14:00:00"); //午休开始时间
        attendGroup.setEndNoonRestTime("15:00:00"); //午休结束时间
        attendGroup.setOffWorkTime("17:00:00"); //下班时间
        attendGroup.setWorkdays("[1,1,1,1,1,0,0]"); //工作日设置
        attendGroup.setAddress("山东济南普利商务中心"); //考勤地点
        attendGroup.setLat(new BigDecimal(117.081293));
        attendGroup.setLng(new BigDecimal(36.671775));
        attendGroup.setAddressRange(1000);//考勤地点范围
        attendGroup.setCreateUserId(CurrentUserHolder.get().getCompanyUserId());
        attendGroup.setCreateTime(new Date());//创建时间
        return attendGroup;
    }
}
